package cn.turboinfo.fuyang.api.gateway.admin.controller.user;

import cn.turboinfo.fuyang.api.domain.admin.usecase.user.AdminReassignUserRoleUseCase;
import cn.turboinfo.fuyang.api.domain.common.service.role.RoleService;
import cn.turboinfo.fuyang.api.domain.common.service.user.SysUserRoleService;
import cn.turboinfo.fuyang.api.domain.common.service.user.SysUserService;
import cn.turboinfo.fuyang.api.domain.common.service.user.UserProfileService;
import cn.turboinfo.fuyang.api.entity.admin.pojo.user.SysUserRole;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.*;
import cn.turboinfo.fuyang.api.gateway.admin.fo.role.CheckableRoleFO;
import cn.turboinfo.fuyang.api.gateway.admin.fo.user.*;
import cn.turboinfo.fuyang.api.gateway.admin.framework.http.ResponseBodyWrapper;
import cn.turboinfo.fuyang.api.gateway.admin.framework.http.fo.LimitDataFO;
import cn.turboinfo.fuyang.api.gateway.admin.framework.http.fo.LimitFO;
import cn.turboinfo.fuyang.api.gateway.admin.framework.http.fo.SortFO;
import cn.turboinfo.fuyang.api.provider.admin.component.security.SecurityEncoder;
import cn.turboinfo.fuyang.api.provider.admin.component.session.AdminSessionHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sunshow.toolkit.core.qbean.api.request.QRequest;
import net.sunshow.toolkit.core.qbean.api.request.QSort;
import net.sunshow.toolkit.core.qbean.api.response.QResponse;
import net.sunshow.toolkit.core.qbean.helper.component.mapper.BeanMapper;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanCreatorHelper;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanSearchHelper;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanUpdaterHelper;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Controller
@ResponseBodyWrapper
@RequestMapping(value = "/admin/user")
public class SysUserController {
    private final SysUserService sysUserService;

    private final SysUserRoleService sysUserRoleService;

    private final RoleService roleService;

    private final AdminSessionHelper sessionHelper;

    private final SecurityEncoder securityEncoder;

    private final AdminReassignUserRoleUseCase reassignUserRoleUseCase;

    private final UserProfileService userProfileService;

    @PostMapping(value = "/modifyPassword")
    public void modifyPassword(@RequestBody @Valid ModifyPasswordFO fo) {
        Long sysUserId = sessionHelper.getSessionSysUserId();

        String originalPassword = securityEncoder.decrypt(fo.getOriginalPassword());
        String newPassword = securityEncoder.decrypt(fo.getNewPassword());

        sysUserService.modifyPassword(sysUserId, originalPassword, newPassword);

        // 可能有 session 变更, 刷新一下
        sessionHelper.refreshSession();
    }

    @RequiresPermissions("adminSysUser:list")
    @GetMapping(value = "/checkAvailable")
    public boolean checkAvailable(@RequestParam String username, @RequestParam(required = false, defaultValue = "0") Long id) {
        if (id != null && id > 0) {
            Optional<SysUser> sysUserOptional = sysUserService.getById(id);
            if (sysUserOptional.isPresent()) {
                SysUser sysUser = sysUserOptional.get();
                if (sysUser.getUsername().equals(username)) {
                    // 可以维持使用自身的不做变动
                    return true;
                }
            } else {
                return false;
            }
        }
        return sysUserService.getByUsername(username).isEmpty();
    }

    @RequiresPermissions("adminSysUser:list")
    @RequestMapping("/list")
    public LimitDataFO<SysUserRespFO> list(@Valid SysUserSearchFO search, LimitFO page, SortFO sort) {
        QRequest request = QBeanSearchHelper.convertQRequest(search);

        if (sort.getSortFields() == null) {
            sort.setSortFields(new String[]{QSysUser.id + "|" + QSort.Order.DESC.name()});
        }

        QResponse<SysUser> sysUserQResponse = sysUserService.findAll(request, page.toQPage(sort.toQSortList()));

        Set<Long> userIdSet = sysUserQResponse.getPagedData().stream()
                .map(SysUser::getId)
                .collect(Collectors.toSet());

        Map<Long, UserProfile> userProfileMap = userProfileService.findByIdCollection(userIdSet)
                .stream()
                .collect(Collectors.toMap(UserProfile::getId, userProfile -> userProfile));

        return LimitDataFO.fromQResponse(sysUserQResponse, sysUser -> {
            SysUserRespFO fo = BeanMapper.map(sysUser, SysUserRespFO.class);
            if (userProfileMap.containsKey(sysUser.getId())) {
                UserProfile userProfile = userProfileMap.get(sysUser.getId());
                fo.setAgenciesId(userProfile.getAgenciesId());
            } else {
                fo.setAgenciesId(0L);
            }

            return fo;


        });
    }

    @RequiresPermissions("adminSysUser:create")
    @PostMapping("/create")
    public SysUserRespFO create(@RequestBody @Valid SysUserCreateFO fo) {
        SysUserCreator.Builder builder = SysUserCreator.builder();
        QBeanCreatorHelper.copyPropertiesToCreatorBuilder(builder, SysUserCreator.class, fo);
        String password = securityEncoder.decrypt(fo.getPassword());
        SysUser sysUser = sysUserService.save(builder.build(), password, fo.getAgenciesId());
        return BeanMapper.map(sysUser, SysUserRespFO.class);
    }


    @RequiresPermissions("adminSysUser:update")
    @PostMapping("/update")
    public SysUserRespFO update(@RequestBody @Valid SysUserUpdateFO fo) {
        SysUserUpdater.Builder builder = SysUserUpdater.builder(fo.getId());
        QBeanUpdaterHelper.copyPropertiesToUpdateBuilder(builder, SysUserUpdater.class, fo);
        SysUser sysUser = sysUserService.update(builder.build(), fo.getAgenciesId());
        return BeanMapper.map(sysUser, SysUserRespFO.class);
    }

    @RequiresPermissions("adminSysUser:delete")
    @PostMapping("/delete")
    public void delete(@RequestParam Long id) {
        Long sysUserId = sessionHelper.getSessionSysUserId();

        if (sysUserId.equals(id)) {
            throw new RuntimeException("不能删除自己");
        }

        SysUser sysUser = sysUserService.getByIdEnsure(id);
        sysUserService.deleteById(sysUser.getId());
    }

    @RequiresPermissions("adminSysUser:resetPassword")
    @PostMapping("/resetPassword")
    public void resetPassword(@RequestBody @Valid ResetPasswordFO fo) {
        String password = securityEncoder.decrypt(fo.getNewPassword());
        sysUserService.resetPassword(fo.getId(), password);
    }

    @RequiresPermissions("adminSysUser:assignRole")
    @GetMapping("/checkableRoleList")
    public List<CheckableRoleFO> checkableRoleList(@RequestParam Long id) {
        SysUser sysUser = sysUserService.getByIdEnsure(id);

        // 用于拥有的角色
        Set<Long> sysUserRoleIdSet = sysUserRoleService.findBySysUserId(sysUser.getId()).stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());

        // 所有角色列表

        return roleService.findAll()
                .stream()
                .map(role -> {
                    CheckableRoleFO fo = new CheckableRoleFO();
                    fo.setRole(role);
                    fo.setChecked(sysUserRoleIdSet.contains(role.getId()));
                    return fo;
                })
                .collect(Collectors.toList());
    }

    @RequiresPermissions("adminSysUser:assignRole")
    @PostMapping("/assignRole")
    public void assignRole(@RequestBody @Valid SysUserAssignRoleFO fo) {
        reassignUserRoleUseCase.execute(AdminReassignUserRoleUseCase.InputData
                .builder()
                .sysUserId(fo.getSysUserId())
                .checkedRoleIds(fo.getCheckedRoleIds())
                .build());
    }
}
